/*  @auther Syt9831
    @content 井字棋PVC算法
*/

#include "abprun.h"
#include "lvgl.h"

static int ab_board[3][3];      //1表示AI落子，-1表示玩家落子
static int ab_turn = 1;     //1表示AI回合，-1表示玩家回合

//初始化虚拟棋盘
void initboard(void)
{
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            ab_board[i][j] = 0;
        }
    }
}

//评估函数
int evaluate(int depth)
{
    int score = checkwin();

    if (checkwin() == 1)
    {
        score = 3 * (100 - depth);
    }
    if (checkwin() == -1)
    {
        score = 3 * (-100 + depth);
    }
    if (checkwin() == -2)
    {
        score = 0;
    }
    //中心位置权重
    if (ab_board[1][1] == 1)
    {
        score += 3;
    }
    if (ab_board[1][1] == -1)
    {
        score -= 3;
    }
    //角落位置权重
    for (int i = 0; i < 3; i += 2)
    {
        for (int j = 0; j < 3; j += 2)
        {
            if (ab_board[i][j] == 1)
            {
                score += 1;
            }
            if (ab_board[i][j] == -1)
            {
                score -= 1;
            }
        }
    }
    return score;
}

//判断输赢，1表示AI胜利，-1表示玩家胜利，-2表示平局
int checkwin(void)
{
    int count;
    for (int i = 0; i < 3; i++)
    {
        int x = ab_board[i][0] != 0 && ab_board[i][0] == ab_board[i][1] && ab_board[i][1] == ab_board[i][2];       //行
        int y = ab_board[0][i] != 0 && ab_board[0][i] == ab_board[1][i] && ab_board[1][i] == ab_board[2][i];       //列
        if (x)
        {
            return (ab_board[i][0] > 0 ? 1 : -1);
        }
        if (y)
        {
            return (ab_board[0][i] > 0 ? 1 : -1);
        }
    }

    if((ab_board[0][0] == 1 && ab_board[1][1] == 1 && ab_board[2][2] == 1) || (ab_board[0][2] == 1 && ab_board[1][1] == 1 && ab_board[2][0] == 1))
    {
        return 1;
    }
    if((ab_board[0][0] == -1 && ab_board[1][1] == -1 && ab_board[2][2] == -1) || (ab_board[0][2] == -1 && ab_board[1][1] == -1 && ab_board[2][0] == -1))
    {
        return -1;
    }

    count = 0;
    //平局判断
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if(ab_board[i][j] == 0)
            {
                count++;        //记录空位个数
            }
        }
    }
    if(count == 0)
    {
        return -2;
    }
    return 0;
}

/*  #作用：
    基于alpha-beta剪枝算法的minimax函数
    #参数：
    int depth:当前递归深度
    int ismax：表示当前玩家是否为最大化玩家（1为最大化玩家:AI，-1为最小化玩家:玩家）
    int alpha：alpha值，用于剪枝（最大化玩家的最佳已知值）
    int beta：beta值，用于剪枝（最小化玩家的已知最佳值）
*/
int minimax(int depth, int ismax, int alpha, int beta)
{
    if (checkwin() != 0)      //如果已经有胜利或平局，则直接返回胜利或平局的评估值
    {
        return evaluate(depth);
    }

    if (ab_turn == 1)      //如果当前是最大化玩家的回合
    {
        int best = -1000;       //初始化best为非常小的值
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (ab_board[i][j] == 0)       //遍历棋盘上每一个格子，如果为空（0）则放置1，代表最大化玩家
                {
                    ab_board[i][j] = 1;
                    int value = minimax(depth + 1, -1 * ab_turn, alpha, beta);        //递归调用minimax函数评估此步之后的棋局
                    best = (value > best) ? value : best;       //更新best值为当前评估中较大的一个
                    alpha = (alpha > best) ? alpha : best;      //更新alpha值
                    ab_board[i][j] = 0;        //恢复棋盘为原状
                    if (beta <= alpha)
                    {
                        return best;     //如果beta ≤ alpha，进行剪枝，直接返回best
                    }
                }
            }
        }
        return best;
    }
    else if (ab_turn == -1)        //如果当前是最小化玩家回合
    {
        int best = 1000;        //初始化best为非常大的值
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (ab_board[i][j] == 0)
                {
                    ab_board[i][j] = -1;       //如果是空白格子，尝试放置-1，代表最小化玩家
                    int value = minimax(depth + 1, -1 * ab_turn, alpha, beta);        //递归调用评估此步后的棋局
                    best = (value < best) ? value : best;       //更新best值为当前评估值中较小的一个
                    beta = (beta < best) ? beta : best;     //更新beta值
                    ab_board[i][j] = 0;        //恢复棋盘格子
                    if (beta <= alpha)
                    {
                        return best;     //如果beta ≤ alpha，进行剪枝，直接返回best
                    }
                }
            }
        }
        return best;
    }
    return 0;
}

/*  #作用：
    用于计算并返回AI在当前局面下的最佳一步棋子的行列位置
    #参数：
    无
*/
int findBestMove(void)
{
    int bestValue = -1000;      //初始化bestvalue为一个非常小的值，用于存储当前最佳评估值
    int bestMoveRow = -1;       //初始化为-1，表示暂未找到最佳行
    int bestMoveCol = -1;       //初始化为-1，表示暂未找到最佳列

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (ab_board[i][j] == 0)     //遍历棋盘，如果为空可以尝试在此处放置棋子
            {
                ab_board[i][j] = 1;      //在空白棋子处尝试放置1（表示AI棋子）
                ab_turn = -1;      //切换到玩家回合
                int moveValue = minimax(0, ab_turn, -1000, 1000);     //调用minimax函数评估此步后的棋局，返回评估值movevalue
                ab_board[i][j] = 0;      //将棋子恢复为原状
                if (moveValue > bestValue)      //更新最佳评估值和最佳步数
                {
                    bestMoveRow = i;
                    bestMoveCol = j;
                    bestValue = moveValue;
                }
            }
        }
    }
    return bestMoveRow * 3 + bestMoveCol;
}

//更新玩家落子
void ismove(int num, int i, int j)
{
    ab_board[i][j] = num;
}

